home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / elm / elm2.4 / src / mailmsg2.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-06  |  41.7 KB  |  1,389 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: mailmsg2.c,v 5.30 1993/06/06 17:53:06 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 5.30 $   $State: Exp $
  6.  *
  7.  *             Copyright (c) 1988-1992 USENET Community Trust
  8.  *             Copyright (c) 1986,1987 Dave Taylor
  9.  *******************************************************************************
  10.  * Bug reports, patches, comments, suggestions should be sent to:
  11.  *
  12.  *    Syd Weinstein, Elm Coordinator
  13.  *    elm@DSI.COM            dsinc!elm
  14.  *
  15.  *******************************************************************************
  16.  * $Log: mailmsg2.c,v $
  17.  * Revision 5.30  1993/06/06  17:53:06  syd
  18.  * Remove extranious clear
  19.  * From: Chip
  20.  *
  21.  * Revision 5.29  1993/05/31  19:31:31  syd
  22.  * Total rewrite of verify_transmission().  The existing code was a monsterous
  23.  * mess and rife with bugs (couldn't forget zero-length messages in send-only
  24.  * mode, prompts were being setup wrong, perms on Canceled.mail not done right,
  25.  * etc. etc. etc.)  Previously, the work had been split among two places,
  26.  * the main code in mail() and the menu in verify_transmission(), and Elm kept
  27.  * bouncing back and forth between the two.  Now, all work is performed in
  28.  * verify_transmission() and it simply returns a send-it/forget-it status.
  29.  * Modified "Canceled.mail" handling so that the files it creates are in
  30.  * an mbox format (i.e. now includes headers as well as message body).
  31.  * From: chip@chinacat.unicom.com (Chip Rosenthal)
  32.  *
  33.  * Revision 5.28  1993/05/14  03:56:19  syd
  34.  * A MIME body-part must end with a newline even when there was no newline
  35.  * at the end of the actual body or the body is null. Otherwise the next
  36.  * mime boundary may not be recognized.  The same goes with the closing
  37.  * boundary too.
  38.  * From: Jukka Ukkonen <ukkonen@csc.fi>
  39.  *
  40.  * Revision 5.27  1993/05/08  20:25:33  syd
  41.  * Add sleepmsg to control transient message delays
  42.  * From: Syd
  43.  *
  44.  * Revision 5.26  1993/05/08  19:54:17  syd
  45.  * fix nesting error
  46.  *
  47.  * Revision 5.25  1993/05/08  19:06:58  syd
  48.  * add not keeping empty cancelled messages
  49.  * From: Syd via request from Phil Richards
  50.  *
  51.  * Revision 5.24  1993/05/08  18:51:32  syd
  52.  * Make Elm quote full names it adds, its easier than checking
  53.  * for specials and only quoting for specials in the name
  54.  * From: Syd
  55.  *
  56.  * Revision 5.23  1993/04/21  01:25:45  syd
  57.  * I'm using Elm 2.4.21 under Linux.  Linux has no Bourne shell.  Each
  58.  * user installs her favorite shell as /bin/sh.  I use Bash 1.12.
  59.  *
  60.  * Elm invokes the mail transport (MTA) like so:
  61.  *
  62.  *    ( ( MTA destination; rm -f tempfile ) & ) < tempfile &
  63.  *
  64.  * This form of command doesn't work with my Bash, in which any command
  65.  * which is backgrounded ("&") gets its stdin attached to /dev/null.
  66.  *
  67.  * The below patch arranges for Elm to call the MTA thusly:
  68.  *
  69.  *    ( MTA destination <tempfile; rm -f tempfile ) &
  70.  * From: decwrl!uunet.UU.NET!fin!chip (Chip Salzenberg)
  71.  *
  72.  * Revision 5.22  1993/04/12  03:57:45  syd
  73.  * Give up and add an Ultrix specific patch. There is a bug in Ispell under
  74.  * ultrix.  The problem is that when ispell returns, the terminal is no
  75.  * longer in raw mode. (Ispell isn't restoring the terminal parameters)
  76.  * From: Scott Ames <scott@cwis.unomaha.edu>
  77.  *
  78.  * Revision 5.21  1993/04/12  02:34:36  syd
  79.  * I have now added a parameter which controls whether want_to clears the
  80.  * line and centers the question or behaves like it did before. I also
  81.  * added a 0 at the end of the parameter list to all the other calls to
  82.  * want_to where a centered question on a clean line is not desirable.
  83.  * From: Jukka Ukkonen <ukkonen@csc.fi>
  84.  *
  85.  * Revision 5.20  1993/02/12  21:35:07  syd
  86.  * fix edit form catting on to end, strcat->strcpy
  87.  * From: Syd
  88.  *
  89.  * Revision 5.19  1993/02/03  17:12:53  syd
  90.  * move more declarations to defs.h, including sleep
  91.  * From: Syd
  92.  *
  93.  * Revision 5.18  1993/02/03  16:45:26  syd
  94.  * A Raw(OFF) was missing so when in mail only mode and one
  95.  * does f)orget, the "Message saved" ends up on wrong screen.
  96.  * Also added \r\n to end of messages to make output look nicer.
  97.  *
  98.  * When composing mail in the builtin editor, it wrapped on /.
  99.  * From: Jan Djarv <Jan.Djarv@sa.erisoft.se>
  100.  *
  101.  * Revision 5.17  1993/02/03  16:36:56  syd
  102.  * Fix where we remove the extra hostbangs and on which fields we do
  103.  * it to include bcc and cc as well as to, and to do it in the file
  104.  * copies as well as the command line.
  105.  *
  106.  * Revision 5.16  1993/01/20  03:02:19  syd
  107.  * Move string declarations to defs.h
  108.  * From: Syd
  109.  *
  110.  * Revision 5.15  1992/12/28  14:24:25  syd
  111.  * Fix problem where it won't let no answer on recall last message
  112.  * From: Syd
  113.  *
  114.  * Revision 5.14  1992/12/24  21:42:01  syd
  115.  * Fix messages and nls messages to match.  Plus use want_to
  116.  * where appropriate.
  117.  * From: Syd, via prompting from Jan Djarv <Jan.Djarv@sa.erisoft.se>
  118.  *
  119.  * Revision 5.13  1992/12/20  05:04:51  syd
  120.  * restore unintnded prefix_chars that caused forwarding without editing
  121.  * to add prefix
  122.  * From: Syd
  123.  *
  124.  * Revision 5.12  1992/12/11  01:58:50  syd
  125.  * Allow for use from restricted shell by putting SHELL=/bin/sh in the
  126.  * environment of spawned mail transport program.
  127.  * From: chip@tct.com (Chip Salzenberg)
  128.  *
  129.  * Revision 5.11  1992/12/07  04:26:26  syd
  130.  * add missing err declare
  131.  * From: Syd
  132.  *
  133.  * Revision 5.10  1992/12/07  03:20:30  syd
  134.  * Change $HOME/Cancelled.mail in message to /fullpath/Cancelled.mail
  135.  * as AFS uses different meaning for $HOME than Elm does and it was
  136.  * confusing to some users.
  137.  * From: Syd
  138.  *
  139.  * Revision 5.9  1992/11/26  01:46:26  syd
  140.  * add Decode option to copy_message, convert copy_message to
  141.  * use bit or for options.
  142.  * From: Syd and bjoerns@stud.cs.uit.no (Bjoern Stabell)
  143.  *
  144.  * Revision 5.8  1992/11/26  00:46:13  syd
  145.  * changes to first change screen back (Raw off) and then issue final
  146.  * error message.
  147.  * From: Syd
  148.  *
  149.  * Revision 5.7  1992/11/22  01:14:20  syd
  150.  * Allow SCO MMDF to use the mmdf library for mailer via execmail.
  151.  * From: Larry Philps <larryp@sco.com>
  152.  *
  153.  * Revision 5.6  1992/11/07  20:29:28  syd
  154.  * These small typos stopped me from making forms, so here is a patch.
  155.  * From: andrew.mcparland@rd.eng.bbc.co.uk (Andrew McParland)
  156.  *
  157.  * Revision 5.5  1992/11/07  16:21:56  syd
  158.  * There is no need to write out the MIME-Version header in subparts
  159.  * From: Klaus Steinberger <Klaus.Steinberger@Physik.Uni-Muenchen.DE>
  160.  *
  161.  * Revision 5.4  1992/10/30  21:04:04  syd
  162.  * fix a bug in the forms reply caused by the Cc: buffer not being
  163.  * cleared.  If one has sent mail just prior to replying to the form and
  164.  * specified a Cc:  address, the form reply is also sent to those Cc:
  165.  * address(es).
  166.  * From: dwolfe@pffft.sps.mot.com (Dave Wolfe)
  167.  *
  168.  * Revision 5.3  1992/10/25  01:47:45  syd
  169.  * fixed a bug were elm didn't call metamail on messages with a characterset,
  170.  * which could be displayed by elm itself, but message is encoded with QP
  171.  * or BASE64
  172.  * From: Klaus Steinberger <Klaus.Steinberger@Physik.Uni-Muenchen.DE>
  173.  *
  174.  * Revision 5.2  1992/10/24  13:44:41  syd
  175.  * There is now an additional elmrc option "displaycharset", which
  176.  * sets the charset supported on your terminal. This is to prevent
  177.  * elm from calling out to metamail too often.
  178.  * Plus a slight documentation update for MIME composition (added examples)
  179.  * From: Klaus Steinberger <Klaus.Steinberger@Physik.Uni-Muenchen.DE>
  180.  *
  181.  * Revision 5.1  1992/10/03  22:58:40  syd
  182.  * Initial checkin as of 2.4 Release at PL0
  183.  *
  184.  *
  185.  ******************************************************************************/
  186.  
  187. /** Interface to allow mail to be sent to users.  Part of ELM  **/
  188.  
  189. #include "headers.h"
  190. #include "s_elm.h"
  191. #include <errno.h>
  192. #include <ctype.h>
  193.  
  194. #ifdef BSD 
  195. #undef tolower
  196. #undef toupper
  197. #endif
  198.  
  199. extern int errno;
  200. extern char version_buff[];
  201.  
  202. char *error_description(), *strip_parens();
  203. char *format_long(), *strip_commas(), *tail_of_string(); 
  204. long ftell();
  205.  
  206. #ifdef SITE_HIDING 
  207.  char *get_ctime_date();
  208. #endif
  209. FILE *write_header_info();
  210.  
  211. /* these are all defined in the mailmsg1.c file! */
  212.  
  213. extern char subject[SLEN], in_reply_to[SLEN], expires[SLEN],
  214.             action[SLEN], priority[SLEN], reply_to[SLEN], to[VERY_LONG_STRING], 
  215.         cc[VERY_LONG_STRING], expanded_to[VERY_LONG_STRING], 
  216.         expanded_reply_to[LONG_STRING],
  217.         expanded_cc[VERY_LONG_STRING], user_defined_header[SLEN],
  218.         bcc[VERY_LONG_STRING], expanded_bcc[VERY_LONG_STRING],
  219.         precedence[SLEN], expires_days[SLEN];
  220.  
  221.  
  222. #ifdef    MIME
  223. int msg_is_multipart;
  224. #endif /* MIME */
  225. long C_L_Position[2];   /*To Remember position of the Content-Length*/
  226. long C_StartData[2];    /*To Remember length of Header Area */
  227. long C_EndData[2];    /* To Remember the end of the BodyPart */
  228.  
  229. int  gotten_key;
  230. char *bounce_off_remote();
  231.  
  232. /*
  233.  * remove_hostbang - Given an expanded list of addresses, remove all
  234.  * occurrences of "thishost!" at the beginning of addresses.
  235.  * This hack is useful in itself, but it is required now because of the
  236.  * kludge disallowing alias expansion on return addresses.
  237.  */
  238.  
  239. void
  240. remove_hostbang(addrs)
  241. char *addrs;
  242. {
  243.     int i, j, hlen, flen;
  244.  
  245.     if ((hlen = strlen(hostname)) < 1)
  246.       return;
  247.  
  248.     flen = strlen(hostfullname);
  249.     i = j = 0;
  250.  
  251.     while (addrs[i]) {
  252.       if (j == 0 || isspace(addrs[j - 1])) {
  253.         if (strncmp(&addrs[i], hostname, hlen) == 0 &&
  254.           addrs[i + hlen] == '!') {
  255.             i += hlen + 1;
  256.             continue;
  257.         }
  258.         if (strncmp(&addrs[i], hostfullname, flen) == 0 &&
  259.           addrs[i + flen] == '!') {
  260.             i += flen + 1;
  261.             continue;
  262.         }
  263.       }
  264.       addrs[j++] = addrs[i++];
  265.     }
  266.     addrs[j] = 0;
  267. }
  268.  
  269. int
  270. mail(copy_msg, edit_message, form)
  271. int  copy_msg, edit_message, form;
  272. {
  273.     /** Given the addresses and various other miscellany (specifically, 
  274.         'copy-msg' indicates whether a copy of the current message should 
  275.         be included, 'edit_message' indicates whether the message should 
  276.         be edited) this routine will invoke an editor for the user and 
  277.         then actually mail off the message. 'form' can be YES, NO, or
  278.         MAYBE.  YES=add "Content-Type: mailform" header, MAYBE=add the
  279.         M)ake form option to last question, and NO=don't worry about it!
  280.         Also, if 'copy_msg' = FORM, then grab the form temp file and use
  281.         that...
  282.         Return TRUE if the main part of the screen has been changed
  283.         (useful for knowing whether a redraw is needed.
  284.     **/
  285.  
  286.     FILE *reply, *real_reply; /* second is post-input buffer */
  287.     char *whole_msg_file, *tempnam();
  288.     char filename[SLEN], fname[SLEN], copy_file[SLEN],
  289.              very_long_buffer[VERY_LONG_STRING], mailerflags[NLEN];
  290.     int ch, sys_status, line_len;
  291.     register int retransmit = FALSE; 
  292.     int      already_has_text = FALSE;        /* we need an ADDRESS */
  293.     int     signature_done = FALSE;
  294.     int     need_redraw = 0;
  295.     int     err;
  296.  
  297.     static int cancelled_msg = 0;
  298.  
  299.     dprint(4, (debugfile, "\nMailing to \"%s\" (with%s editing)\n",
  300.           expanded_to, edit_message? "" : "out"));
  301.     
  302.     gotten_key = 0;        /* ignore previously gotten encryption key */
  303.  
  304.     /** first generate the temporary filename **/
  305.  
  306.     sprintf(filename,"%s%s%d", temp_dir, temp_file, getpid());
  307.  
  308.     /** if possible, let's try to recall the last message? **/
  309.  
  310.     if (! batch_only && copy_msg != FORM && user_level != 0)
  311.       retransmit = recall_last_msg(filename, copy_msg, &cancelled_msg, 
  312.                &already_has_text);
  313.  
  314.     /** if we're not retransmitting, create the file.. **/
  315.  
  316.     if (! retransmit)
  317.       if ((reply = fopen(filename,"w")) == NULL) {
  318.         err = errno;
  319.         dprint(1, (debugfile, 
  320.                "Attempt to write to temp file %s failed with error %s (mail)\n",
  321.          filename, error_description(err)));
  322.         if(batch_only) {
  323.           MCprintf(catgets(elm_msg_cat, ElmSet, ElmCouldNotCreateFile,
  324.         "Could not create file %s (%s)."),
  325.         filename, error_description(err));
  326.           printf("\n");
  327.         } else
  328.           error2(catgets(elm_msg_cat, ElmSet, ElmCouldNotCreateFile,
  329.         "Could not create file %s (%s)."),
  330.         filename, error_description(errno));
  331.         return(need_redraw);
  332.       }
  333.  
  334.     chown (filename, userid, groupid);
  335.  
  336.     /* copy the message from standard input */
  337.     if (batch_only) {
  338.       while (line_len = fread(very_long_buffer, 1, sizeof(very_long_buffer), stdin))
  339.         fwrite(very_long_buffer, 1, line_len, reply);
  340.     }
  341.  
  342.     /** if there is an included file, copy it into the temp file **/
  343.     if (*included_file) {
  344.       FILE *input;
  345.       if ((input = fopen(included_file,"r")) == NULL) {
  346.         dprint(1, (debugfile, 
  347.               "Can't open included file %s.  Failed with error %s (mail)\n",
  348.           included_file, error_description(errno)));
  349.         error2(catgets(elm_msg_cat, ElmSet, ElmCouldNotOpenFile,
  350.           "Could not open file %s."), included_file);
  351.         return(need_redraw);
  352.       }
  353.  
  354.       while (fgets(very_long_buffer, VERY_LONG_STRING, input) != NULL) 
  355.         fputs(very_long_buffer, reply);
  356.  
  357.       fclose(input);
  358.       already_has_text = TRUE;
  359.     }
  360.  
  361.     if (copy_msg == FORM) {
  362.       sprintf(fname, "%s%s%d", temp_dir, temp_form_file, getpid());
  363.       fclose(reply);    /* we can't retransmit a form! */
  364.       if (access(fname,ACCESS_EXISTS) != 0) {
  365.         if(batch_only) {
  366.           printf(catgets(elm_msg_cat, ElmSet, ElmCouldNotFindForm,
  367.         "Couldn't find forms file!"));
  368.           printf("\n");
  369.         } else
  370.           error(catgets(elm_msg_cat, ElmSet, ElmCouldNotFindForm,
  371.         "Couldn't find forms file!"));
  372.         return(need_redraw);
  373.       }
  374.       dprint(4, (debugfile, "-- renaming existing file %s to file %s --\n",
  375.           fname, filename));
  376.       rename(fname, filename);
  377.  
  378.       /* kill leftover headers since forms reply skips regular init */
  379.       expires[0] = '\0';
  380.       expires_days[0] = '\0';
  381.       action[0] = '\0';
  382.       priority[0] = '\0';
  383.       reply_to[0] = '\0';
  384.       expanded_reply_to[0] = '\0';
  385.       cc[0] = '\0';
  386.       expanded_cc[0] = '\0';
  387.       user_defined_header[0] = '\0';
  388.       bcc[0] = '\0';
  389.       expanded_bcc[0] = '\0';
  390.       precedence[0] = '\0';
  391.     }
  392.     else if (copy_msg && ! retransmit) {  /* if retransmit we have it! */
  393.       if (attribution[0]) {
  394.         fprintf(reply, attribution, headers[current-1]->from);
  395.         fputc('\n', reply);
  396.       }
  397.       else if (forwarding) {
  398.         fputs("Forwarded message:\n", reply);
  399.       }
  400.       if (edit_message) {
  401.         copy_message(prefixchars, reply,
  402.         ( noheader ? CM_REMOVE_HEADER : 0 ) | CM_MMDF_HEAD | CM_DECODE);
  403.         already_has_text = TRUE;    /* we just added it, right? */
  404.       }
  405.       else
  406.         copy_message("", reply,
  407.         ( noheader ? CM_REMOVE_HEADER : 0 ) | CM_MMDF_HEAD);
  408.     }
  409.  
  410.         /* append signature now if we are going to use an external editor */
  411.     /* Don't worry about the remote/local determination too much */
  412.  
  413.         if (already_has_text || 
  414.            (strcmp(editor,"builtin") != 0 && strcmp(editor,"none") != 0)) {
  415.          signature_done = TRUE;
  416.              if (!retransmit && copy_msg != FORM) 
  417.            already_has_text |= append_sig(reply);
  418.     }
  419.  
  420.     if (! retransmit && copy_msg != FORM)
  421.       if (reply != NULL)
  422.         (void) fclose(reply);    /* on replies, it won't be open! */
  423.  
  424.     /** Edit the message **/
  425.  
  426.     /* calculate default save_file name */
  427.     if(auto_cc) {
  428.       if(save_by_name) {
  429.         if(force_name) {
  430.           strcpy(copy_file, "=");    /* signals save by 'to' logname */
  431.         } else {
  432.           strcpy(copy_file, "=?");    /* conditional save by 'to' logname */
  433.         }
  434.       } else {
  435.         strcpy(copy_file, "<");    /* signals save to sentmail */
  436.       }
  437.     } else *copy_file = '\0';    /* signals to not save a copy */
  438.  
  439.     /* ask the user to confirm transmission of the message */
  440.     if (!batch_only) {
  441.         ch = (edit_message? 'e' : '\0');
  442.         if (verify_transmission(filename, &form, &need_redraw,
  443.             already_has_text, copy_file, ch) != 0) {
  444.         cancelled_msg = (bytes(filename) > 0);
  445.         return need_redraw;
  446.         }
  447.         if (form == YES && format_form(filename) < 1) {
  448.         cancelled_msg = (bytes(filename) > 0);
  449.         return need_redraw;
  450.         }
  451.     }
  452.  
  453.     if ((reply = fopen(filename,"r")) == NULL) {
  454.         err = errno;
  455.         dprint(1, (debugfile,
  456.         "Attempt to open file %s for reading failed with error %s (mail)\n",
  457.         filename, error_description(err)));
  458.         if (!batch_only) {
  459.         error1(catgets(elm_msg_cat, ElmSet, ElmCouldNotOpenReply,
  460.             "Could not open reply file (%s)."), error_description(err));
  461.         } else {
  462.         printf(catgets(elm_msg_cat, ElmSet, ElmCouldNotOpenReply,
  463.             "Could not open reply file (%s)."), error_description(err));
  464.         putchar('\n');
  465.         }
  466.         return need_redraw;
  467.     }
  468.  
  469.     cancelled_msg = FALSE;    /* it ain't cancelled, is it? */
  470.  
  471.     /** ask about bounceback if the user wants us to.... **/
  472.  
  473.     if (uucp_hops(to) > bounceback && bounceback > 0 && copy_msg != FORM) 
  474.       if (verify_bounceback() == TRUE) {
  475.         if (strlen(cc) > 0) strcat(expanded_cc, ", ");
  476.         strcat(expanded_cc, bounce_off_remote(to));
  477.       }
  478.  
  479. #ifdef    MIME
  480.     /* Look if its a Multimedia/multipart Message */
  481.     msg_is_multipart = check_for_multipart(reply);
  482.  
  483.     if (msg_is_multipart == -1) {
  484.         return(need_redraw);
  485.     }
  486. #endif /* MIME */
  487.  
  488.     /** grab a copy if the user so desires... **/
  489.  
  490.     remove_hostbang(expanded_to);
  491.     remove_hostbang(expanded_cc);
  492.     remove_hostbang(expanded_bcc);
  493.  
  494.     if (*copy_file) /* i.e. if copy_file contains a name */
  495.       save_copy(expanded_to, expanded_cc, expanded_bcc,
  496.            filename, copy_file, form);
  497.  
  498.     /** write all header information into whole_msg_file **/
  499.  
  500.     if((whole_msg_file=tempnam(temp_dir, "snd.")) == NULL) {
  501.       dprint(1, (debugfile, "couldn't make temp file nam! (mail)\n"));
  502.       if(batch_only) {
  503.         printf(catgets(elm_msg_cat, ElmSet, ElmCouldNotMakeTemp,
  504.         "Sorry - couldn't make temp file name!"));
  505.         printf("\n");
  506.       } else if(mail_only)
  507.         error(catgets(elm_msg_cat, ElmSet, ElmCouldNotMakeTemp,
  508.         "Sorry - couldn't make temp file name."));
  509.       else
  510.         set_error(catgets(elm_msg_cat, ElmSet, ElmCouldNotMakeTemp,
  511.         "Sorry - couldn't make temp file name."));
  512.       return(need_redraw);
  513.     }
  514.  
  515.     /** try to write headers to new temp file **/
  516.  
  517.     dprint(6, (debugfile, "Composition file='%s' and mail buffer='%s'\n", 
  518.             filename, whole_msg_file));
  519.  
  520.     dprint(2,(debugfile,"--\nTo: %s\nCc: %s\nBcc: %s\nSubject: %s\n---\n", 
  521.           expanded_to, expanded_cc, expanded_bcc, subject));
  522.  
  523.     if ((real_reply = 
  524.        write_header_info(whole_msg_file, expanded_to,
  525.          expanded_cc, expanded_bcc, form == YES, FALSE)) == NULL) {
  526.  
  527.       /** IT FAILED!!  MEIN GOTT!  Use a dumb mailer instead! **/
  528.  
  529.       dprint(3, (debugfile, "** write_header failed: %s\n", 
  530.          error_description(errno)));
  531.  
  532.       if (cc[0] != '\0')          /* copies! */
  533.         sprintf(expanded_to,"%s %s", expanded_to, expanded_cc);
  534.  
  535.       quote_args(very_long_buffer, strip_parens(strip_commas(expanded_to)));
  536.       strcpy(expanded_to, very_long_buffer);
  537.  
  538.       sprintf(very_long_buffer, "(%s -s \"%s\" %s < %s ; %s %s) &",
  539.           mailx, subject, expanded_to, filename, remove_cmd, filename);
  540.  
  541.       if(batch_only) {
  542.         printf(catgets(elm_msg_cat, ElmSet, ElmUsedDumpMailer,
  543.         "Message sent using dumb mailer %s."), mailx);
  544.         printf("\n");
  545.       } else
  546.         error1(catgets(elm_msg_cat, ElmSet, ElmUsedDumpMailer,
  547.         "Message sent using dumb mailer %s."), mailx);
  548.         if (sleepmsg > 0)
  549.         sleep(sleepmsg);
  550.  
  551.     }
  552.     else {
  553.  
  554.       C_StartData[0] = ftell(real_reply);
  555.  
  556.       copy_message_across(reply, real_reply, FALSE);
  557.  
  558.           /* Append signature if not done earlier */
  559.  
  560.           if (!signature_done && !retransmit && copy_msg != FORM)
  561.                append_sig(real_reply);
  562.       
  563. #ifdef MIME
  564.       if (!copy_msg != FORM && msg_is_multipart) {
  565.         fprintf(real_reply, "\n--%s--\n", MIME_BOUNDARY);
  566.         if (C_L_Position[1] != 0L) {
  567.           C_EndData[1] = ftell(real_reply);
  568.           C_L_Position[1] = fseek(real_reply, C_L_Position[1], 0);
  569.           fprintf(real_reply, "%d", C_EndData[1] - C_StartData[1]);
  570.           fseek(real_reply, C_EndData[1], 0);
  571.         }
  572.       }
  573. #endif
  574.  
  575.       C_EndData[0] = ftell(real_reply);
  576.         
  577.       fseek(real_reply, C_L_Position[0], 0);
  578.       fprintf(real_reply, "%d", C_EndData[0] - C_StartData[0]);
  579.       fclose(real_reply);
  580.  
  581.       if (cc[0] != '\0')                           /* copies! */
  582.         sprintf(expanded_to,"%s %s", expanded_to, expanded_cc);
  583.  
  584.       if (bcc[0] != '\0') {
  585.         strcat(expanded_to, " ");
  586.         strcat(expanded_to, expanded_bcc);
  587.       }
  588.  
  589.       if (strcmp(sendmail, mailer) == 0
  590. #ifdef SITE_HIDING
  591.           && ! is_a_hidden_user(username)
  592. #endif
  593.       ) {
  594.         strcpy(mailerflags, (sendmail_verbose ? smflagsv : smflags));
  595.         if (metoo) strcat(mailerflags, smflagmt);
  596.       } else if (strcmp(submitmail, mailer) == 0)
  597.         strcpy(mailerflags, submitflags_s);
  598.       else if (strcmp(execmail, mailer) == 0) {
  599.         strcpy(mailerflags, (sendmail_verbose ? emflagsv : emflags));
  600.         if (metoo) strcat(mailerflags, emflagmt);
  601.       } else
  602.         mailerflags[0] ='\0';
  603.  
  604.       if (strcmp(submitmail, mailer) == 0)
  605.         strcpy(expanded_to, " ");
  606.       else {
  607.         quote_args(very_long_buffer, strip_parens(strip_commas(expanded_to)));
  608.         strcpy(expanded_to, very_long_buffer);
  609.       }
  610.  
  611.       sprintf(very_long_buffer,"(%s %s %s < %s ; %s %s) &", 
  612.         mailer, mailerflags, expanded_to, whole_msg_file,
  613.         remove_cmd, whole_msg_file);
  614.     }
  615.     
  616.     fclose(reply);
  617.  
  618.     if(batch_only) {
  619.       printf(catgets(elm_msg_cat, ElmSet, ElmSendingMail,
  620.         "Sending mail..."));
  621.       printf("\n");
  622.     } else {
  623.       PutLine0(LINES,0,catgets(elm_msg_cat, ElmSet, ElmSendingMail,
  624.         "Sending mail..."));
  625.       CleartoEOLN();
  626.     }
  627.  
  628.     /* Take note of mailer return value */
  629.  
  630.     if ( sys_status = system_call(very_long_buffer, SY_ENV_SHELL) ) {
  631.         /* problem case: */
  632.         if (mail_only || batch_only) {
  633.            printf("\r\n");
  634.            printf(catgets(elm_msg_cat, ElmSet, ElmMailerReturnedError,
  635.             "mailer returned error status %d"), sys_status);
  636.            printf("\r\n");
  637.         } else {
  638.            sprintf(very_long_buffer, catgets(elm_msg_cat, ElmSet, ElmMailerReturnedError,
  639.             "mailer returned error status %d"), sys_status);
  640.            set_error(very_long_buffer);
  641.         }
  642.     } else {
  643.         /* Success case: */
  644.         if(batch_only) {
  645.           printf(catgets(elm_msg_cat, ElmSet, ElmMailSent, "Mail sent!"));
  646.               printf("\n");
  647.         } else if(mail_only)
  648.           error(catgets(elm_msg_cat, ElmSet, ElmMailSent, "Mail sent!"));
  649.         else
  650.           set_error(catgets(elm_msg_cat, ElmSet, ElmMailSent, "Mail sent!"));
  651.     }
  652.  
  653.     /* Unlink temp file now.
  654.      * This is a precaution in case the message was encrypted.
  655.      * I.e. even though this file is readable by the owner only,
  656.      * encryption is supposed to hide things even from someone
  657.      * with root privelges. The best we can do is not let this
  658.      * file just hang after we're finished with it.
  659.      */
  660.     (void)unlink(filename);
  661.  
  662.     return(need_redraw);
  663. }
  664.  
  665. mail_form(address, subj)
  666. char *address, *subj;
  667. {
  668.     /** copy the appropriate variables to the shared space... */
  669.  
  670.     strcpy(subject, subj);
  671.     strcpy(to, address);
  672.     strcpy(expanded_to, address);
  673.  
  674.     return(mail(FORM, NO, NO));
  675. }
  676.  
  677. int
  678. recall_last_msg(filename, copy_msg, cancelled_msg, already_has_text)
  679. char *filename;
  680. int  copy_msg, *cancelled_msg, *already_has_text;
  681. {
  682.     char ch;
  683.     char msg[SLEN];
  684.  
  685.     /** If filename exists and we've recently cancelled a message,
  686.         the ask if the user wants to use that message instead!  This
  687.         routine returns TRUE if the user wants to retransmit the last
  688.         message, FALSE otherwise...
  689.     **/
  690.  
  691.     register int retransmit = FALSE;
  692.  
  693.     if (access(filename, EDIT_ACCESS) == 0 && *cancelled_msg) {
  694.       Raw(ON);
  695.       CleartoEOLN();
  696.       if (copy_msg)
  697.         MCsprintf(msg, catgets(elm_msg_cat, ElmSet, ElmRecallLastInstead,
  698.              "Recall last kept message instead? (%c/%c) "),
  699.              *def_ans_yes, *def_ans_no);
  700.       else
  701.         MCsprintf(msg, catgets(elm_msg_cat, ElmSet, ElmRecallLastKept,
  702.              "Recall last kept message? (%c/%c) "),
  703.              *def_ans_yes, *def_ans_no);
  704.       do {
  705.         ch = want_to(msg, '\0', LINES-1, 0);
  706.         if (ch == *def_ans_yes) {
  707.               retransmit++;
  708.           *already_has_text = TRUE;
  709.         } else if (ch != *def_ans_no) {
  710.           Write_to_screen("%c??", 1, 07);    /* BEEP */
  711.           if (sleepmsg > 0)
  712.             sleep((sleepmsg + 1) / 2);
  713.           ch = 0;
  714.         }
  715.       } while (ch == 0);
  716.  
  717.       fflush(stdout);
  718.  
  719.       *cancelled_msg = 0;
  720.     }
  721.  
  722.     return(retransmit);
  723. }
  724.  
  725.  
  726. /*
  727.  * verify_transmission() - Ask the user to confirm transmission of the
  728.  * message.  Returns 0 to send it, -1 to forget it.
  729.  */
  730. int
  731. verify_transmission(filename, form_p, need_redraw_p,
  732.     already_has_text, copy_file, force_cmd)
  733. char *filename;        /* pathname to mail mssg composition file    */
  734. int  *form_p;        /* pointer to form message state        */
  735. int *need_redraw_p;    /* pointer to flag indicating screen stepped on    */
  736. int already_has_text;    /* indicates there is already text in the mssg    */
  737. char *copy_file;    /* pointer to buffer holding copy file name    */
  738. int force_cmd;        /* command to do, '\0' to prompt user for cmd    */
  739. {
  740.     char *prompt_mssg;        /* message to display prompting for cmd    */
  741.     char prompt_menu[SLEN];    /* menu of available commands        */
  742.     int bad_cmd;        /* set TRUE to bitch about user's entry    */
  743.     int did_prompt;        /* TRUE if cmd prompted for and entered    */
  744.     int prev_form;        /* "*form_p" value last time thru loop    */
  745.     int cmd;            /* command to perform            */
  746.     char lbuf[VERY_LONG_STRING];
  747.     int x_coord, y_coord;
  748.  
  749.     prev_form = *form_p + 1;    /* force build of prompt strings    */
  750.     bad_cmd = FALSE;        /* nothing to complain about yet    */
  751.  
  752.     for (;;) {
  753.  
  754.     /* build up prompt and menu strings */
  755.     if (prev_form == *form_p) {
  756.         ; /* not changed - no need to rebuild the strings */
  757.     } else if (user_level == 0) {
  758.         prompt_mssg = catgets(elm_msg_cat, ElmSet, ElmVfyPromptPleaseChoose,
  759.         "Please choose one of the following options by parenthesized letter: s");
  760.         strcpy(prompt_menu, catgets(elm_msg_cat, ElmSet, ElmVfyMenuUser0,
  761.         "e)dit message, edit h)eaders, s)end it, or f)orget it."));
  762.     } else {
  763.         prompt_mssg = catgets(elm_msg_cat, ElmSet, ElmVfyPromptAndNow,
  764.         "And now: s");
  765.         switch (*form_p) {
  766.         case PREFORMATTED:
  767.         strcpy(prompt_menu, "");
  768.         break;
  769.         case YES:
  770.         strcpy(prompt_menu, catgets(elm_msg_cat, ElmSet,
  771.             ElmVfyMenuEditForm, "e)dit form, "));
  772.         break;
  773.         case MAYBE:
  774.         strcpy(prompt_menu, catgets(elm_msg_cat, ElmSet,
  775.             ElmVfyMenuEditMake, "e)dit msg, m)ake form, "));
  776.         break;
  777.         default:
  778.         strcpy(prompt_menu, catgets(elm_msg_cat, ElmSet,
  779.             ElmVfyMenuEditMsg, "e)dit message, "));
  780.         break;
  781.         }
  782.         strcat(prompt_menu, catgets(elm_msg_cat, ElmSet, ElmVfyMenuVfyCpy,
  783.         "h)eaders, c)opy, "));
  784. #ifdef ISPELL
  785.         strcat(prompt_menu, catgets(elm_msg_cat, ElmSet, ElmVfyMenuIspell,
  786.         "i)spell, "));
  787. #endif
  788. #ifdef ALLOW_SUBSHELL
  789.         strcat(prompt_menu, catgets(elm_msg_cat, ElmSet, ElmVfyMenuShell,
  790.         "!)shell, "));
  791. #endif
  792.         strcat(prompt_menu, catgets(elm_msg_cat, ElmSet, ElmVfyMenuSndFgt,
  793.         "s)end, or f)orget"));
  794.     }
  795.     prev_form = *form_p;
  796.  
  797.     /* complain if last entry was bad */
  798.     if (bad_cmd) {
  799.         Write_to_screen("%c??", 1, 07);
  800.         if (sleepmsg > 0)
  801.         sleep((sleepmsg + 1) / 2);
  802.         bad_cmd = FALSE;
  803.     }
  804.  
  805.     /* if we don't have a cmd, display prompt and get response from user */
  806.     if (force_cmd != '\0') {
  807.         cmd = tolower(force_cmd);
  808.         force_cmd = '\0';
  809.         did_prompt = FALSE;
  810.     } else {
  811.         MoveCursor(LINES-2, 0);
  812.         CleartoEOS();
  813.         PutLine0(LINES-2, 0, prompt_mssg);
  814.         GetXYLocation(&x_coord, &y_coord);
  815.         y_coord--; /* backspace over default answer */
  816.         Centerline(LINES-1, prompt_menu);
  817.         fflush(stdin);
  818.         fflush(stdout);
  819.         Raw(ON); /* double check... testing only... */
  820.         MoveCursor(x_coord, y_coord);
  821.         cmd = ReadCh();
  822.         cmd = tolower(cmd);
  823.         did_prompt = TRUE;
  824.     }
  825.  
  826.     /* handle command */
  827.     switch (cmd) {
  828.  
  829.     case '\n':
  830.     case '\r':
  831.     case 's':
  832.         if (did_prompt)
  833.         Write_to_screen("Send", 0);
  834.         return 0;
  835.         /*NOTREACHED*/
  836.  
  837.     case 'f': 
  838.         if (did_prompt)
  839.         Write_to_screen("Forget", 0);
  840.         if (bytes(filename) <= 0) {
  841.         ; /* forget about empty files */
  842.         } else if (mail_only) {
  843.         sprintf(lbuf, "%s/%s", home, dead_letter);
  844.         (void) append_copy_to_file(to, cc, bcc, lbuf, filename,
  845.             *form_p);
  846.         } else if (user_level > 0) {
  847.         set_error(catgets(elm_msg_cat, ElmSet, ElmVfyMessageKept,
  848.             "Message kept.  Can be restored at next f)orward, m)ail or r)eply."));
  849.         }
  850.         return -1;
  851.         /*NOTREACHED*/
  852.  
  853.     case 'c':
  854.         if (did_prompt)
  855.         Write_to_screen("Copy file", 0);
  856.         if (name_copy_file(copy_file) != 0)
  857.         *need_redraw_p = TRUE;
  858.         break;
  859.  
  860.     case 'e':
  861.         if (did_prompt)
  862.         Write_to_screen("Edit", 0);
  863.         if (*form_p == PREFORMATTED) {
  864.         bad_cmd = TRUE;
  865.         } else {
  866.         if (*form_p == YES)
  867.             *form_p = MAYBE;
  868.         *need_redraw_p = TRUE;
  869.         if (edit_the_message(filename, already_has_text) != 0)
  870.             return -1;
  871.         }
  872.         break;
  873.  
  874.     case 'h':
  875.         if (did_prompt)
  876.         Write_to_screen("Headers", 0);
  877.         (void) edit_headers();
  878.         *need_redraw_p = TRUE;
  879.         break;
  880.  
  881.     case 'm':
  882.         if (*form_p != MAYBE) {
  883.         bad_cmd = TRUE;
  884.         } else {
  885.         switch (check_form_file(filename)) {
  886.         case -1:
  887.             /* couldn't open file??? */
  888.             return -1;
  889.         case 0:
  890.             Write_to_screen(catgets(elm_msg_cat, ElmSet,
  891.             ElmVfyNoFieldsInForm, "No fields in form!\007"), 0);
  892.             if (sleepmsg > 0)
  893.             sleep(sleepmsg);
  894.             break;
  895.         default:
  896.             /* looks like a good form */
  897.             *form_p = YES;
  898.             break;
  899.         }
  900.         }
  901.         break;
  902.  
  903. #ifdef ISPELL
  904.     case 'i':
  905.         if (did_prompt)
  906.         Write_to_screen("Ispell", 0);
  907.         if (*form_p == PREFORMATTED) {
  908.         bad_cmd = TRUE;
  909.         } else {
  910.         if (*form_p == YES)
  911.             *form_p = MAYBE;
  912.         sprintf(lbuf, "%s %s %s",
  913.             ISPELL_PATH, ISPELL_OPTIONS, filename);
  914.         system_call(lbuf, SY_ENAB_SIGHUP);
  915.         *need_redraw_p = TRUE;
  916. #ifdef ultrix
  917.         /* I'm told this is required to work around some sort of bug */
  918.         force_raw();
  919. #endif
  920.         }
  921.         break;
  922. #endif
  923.  
  924. #ifdef ALLOW_SUBSHELL
  925.     case '!':
  926.         if (subshell() != 0) {
  927.         ClearScreen();
  928.         *need_redraw_p = TRUE;
  929.         }
  930.         break;
  931. #endif
  932.  
  933.     default:
  934.         bad_cmd = TRUE;
  935.         break;
  936.  
  937.     }
  938.  
  939.     }
  940.  
  941. }
  942.  
  943.  
  944. FILE *
  945. write_header_info(filename, long_to, long_cc, long_bcc, form, copy)
  946. char *filename, *long_to, *long_cc, *long_bcc;
  947. int   form, copy;
  948. {
  949.     /** Try to open filedesc as the specified filename.  If we can,
  950.         then write all the headers into the file.  The routine returns
  951.         'filedesc' if it succeeded, NULL otherwise.  Added the ability
  952.         to have backquoted stuff in the users .elmheaders file!
  953.         If copy is TRUE, then treat this as the saved copy of outbound
  954.         mail.
  955.     **/
  956.  
  957.     char opentype[3];
  958.     long time(), thetime;
  959.     char *ctime();
  960.     static FILE *filedesc;        /* our friendly file descriptor  */
  961.         char to_buf[VERY_LONG_STRING];
  962.     int err;
  963.  
  964. #ifdef SITE_HIDING
  965.     char  buffer[SLEN];
  966.     int   is_hidden_user;        /* someone we should know about?  */
  967. #endif
  968. #ifdef MMDF
  969.     int   is_submit_mailer;        /* using submit means change From: */
  970. #endif /* MMDF */
  971.  
  972.     char  *get_arpa_date();
  973.  
  974.     if(copy) 
  975.         strcpy(opentype, "r+");
  976.     else
  977.         strcpy(opentype, "w+");
  978.  
  979.     save_file_stats(filename);
  980.  
  981.     filedesc = fopen(filename, opentype);
  982.     if (copy && filedesc == NULL)
  983.       filedesc = fopen(filename, "w+");
  984.  
  985.     if (filedesc == NULL) {
  986.       err = errno;
  987.       dprint(1, (debugfile,
  988.         "Attempt to open file %s for writing failed! (write_header_info)\n",
  989.          filename));
  990.       dprint(1, (debugfile, "** %s **\n\n", error_description(err)));
  991.       error2(catgets(elm_msg_cat, ElmSet, ElmErrorTryingToWrite,
  992.         "Error %s encountered trying to write to %s."), 
  993.         error_description(err), filename);
  994.       if (sleepmsg > 0)
  995.         sleep(sleepmsg);
  996.       return(NULL);        /* couldn't open it!! */
  997.     }
  998.  
  999.     if (copy) {
  1000.         /* Position to the end of the file */
  1001.         fseek(filedesc, 0L, 2);
  1002.     }
  1003.  
  1004.     restore_file_stats(filename);
  1005.  
  1006.     if(copy) {    /* Add top line that mailer would add */
  1007. #ifdef MMDF
  1008.       fprintf(filedesc, MSG_SEPARATOR);
  1009. #endif /* MMDF */
  1010.       thetime = time((long *) 0);
  1011.       fprintf(filedesc,"From %s %s", username, ctime(&thetime));
  1012. #ifdef MMDF
  1013.     } else if (strcmp(submitmail,mailer) == 0) {
  1014.       sprintf(to_buf, "%s %s %s", long_to, long_cc, long_bcc);
  1015.       do_mmdf_addresses(filedesc, strip_parens(strip_commas(to_buf)));
  1016. #endif /* MMDF */
  1017.     }
  1018.  
  1019. #ifdef SITE_HIDING
  1020.     if ( !copy && (is_hidden_user = is_a_hidden_user(username))) {
  1021.       /** this is the interesting part of this trick... **/
  1022.       sprintf(buffer, "From %s!%s %s\n",  HIDDEN_SITE_NAME,
  1023.           username, get_ctime_date());
  1024.       fprintf(filedesc, "%s", buffer);
  1025.       dprint(1,(debugfile, "\nadded: %s", buffer));
  1026.       /** so is this perverted or what? **/
  1027.     }
  1028. #endif
  1029.  
  1030.  
  1031.     /** Subject moved to top of headers for mail because the
  1032.         pure System V.3 mailer, in its infinite wisdom, now
  1033.         assumes that anything the user sends is part of the 
  1034.         message body unless either:
  1035.         1. the "-s" flag is used (although it doesn't seem
  1036.            to be supported on all implementations?? )
  1037.         2. the first line is "Subject:".  If so, then it'll
  1038.            read until a blank line and assume all are meant
  1039.            to be headers.
  1040.         So the gory solution here is to move the Subject: line
  1041.         up to the top.  I assume it won't break anyone elses program
  1042.         or anything anyway (besides, RFC-822 specifies that the *order*
  1043.         of headers is irrelevant).  Gahhhhh....
  1044.     **/
  1045.  
  1046.     fprintf(filedesc, "Subject: %s\n", subject);
  1047.  
  1048.       fprintf(filedesc, "To: %s\n", format_long(long_to, strlen("To:")));
  1049.  
  1050.     fprintf(filedesc,"Date: %s\n", get_arpa_date());
  1051.  
  1052. #ifndef DONT_ADD_FROM
  1053. #ifdef MMDF
  1054.     is_submit_mailer = (strcmp(submitmail,mailer) == 0);
  1055. #endif /* MMDF */
  1056. /*
  1057.  *    quote full user name in case it contains specials
  1058.  */
  1059. # ifdef SITE_HIDING
  1060. #    ifdef MMDF
  1061.     if (is_submit_mailer)
  1062.       fprintf(filedesc,"From: \"%s\" <%s>\n", full_username, username);
  1063.     else
  1064. #    endif /* MMDF */
  1065.     if (is_hidden_user)
  1066.       fprintf(filedesc,"From: \"%s\" <%s!%s!%s>\n", full_username,
  1067.           hostname, HIDDEN_SITE_NAME, username);
  1068.     else
  1069.       fprintf(filedesc,"From: \"%s\" <%s!%s>\n", full_username,
  1070.           hostname, username);
  1071. # else
  1072. #  ifdef  INTERNET
  1073. #   ifdef  USE_DOMAIN
  1074. #    ifdef MMDF
  1075.     if (is_submit_mailer)
  1076.       fprintf(filedesc,"From: \"%s\" <%s>\n", full_username, username);
  1077.     else
  1078. #    endif /* MMDF */
  1079.       fprintf(filedesc,"From: \"%s\" <%s@%s>\n", full_username, 
  1080.         username, hostfullname);
  1081. #   else
  1082. #    ifdef MMDF
  1083.     if (is_submit_mailer)
  1084.       fprintf(filedesc,"From: \"%s\" <%s>\n", full_username, username);
  1085.     else
  1086. #    endif /* MMDF */
  1087.     fprintf(filedesc,"From: \"%s\" <%s@%s>\n", full_username,
  1088.         username, hostname);
  1089. #   endif
  1090. #  else
  1091. #    ifdef MMDF
  1092.     if (is_submit_mailer)
  1093.       fprintf(filedesc,"From: \"%s\" <%s>\n", full_username, username);
  1094.     else
  1095. #    endif /* MMDF */
  1096.     fprintf(filedesc,"From: \"%s\" <%s!%s>\n", full_username,
  1097.         hostname, username);
  1098. #  endif
  1099. # endif
  1100. #endif
  1101.  
  1102.     if (cc[0] != '\0')
  1103.         fprintf(filedesc, "Cc: %s\n", format_long(long_cc, strlen("Cc: ")));
  1104.  
  1105.     if (copy && (bcc[0] != '\0'))
  1106.         fprintf(filedesc, "Bcc: %s\n", format_long(long_bcc, strlen("Bcc: ")));
  1107.  
  1108.     if (strlen(action) > 0)
  1109.         fprintf(filedesc, "Action: %s\n", action);
  1110.     
  1111.     if (strlen(priority) > 0)
  1112.         fprintf(filedesc, "Priority: %s\n", priority);
  1113.  
  1114.     if (strlen(precedence) > 0)
  1115.         fprintf(filedesc, "Precedence: %s\n", precedence);
  1116.     
  1117.     if (strlen(expires) > 0)
  1118.         fprintf(filedesc, "Expires: %s\n", expires);
  1119.     
  1120.     if (strlen(expanded_reply_to) > 0)
  1121.         fprintf(filedesc, "Reply-To: %s\n", expanded_reply_to);
  1122.  
  1123.     if (strlen(in_reply_to) > 0)
  1124.         fprintf(filedesc, "In-Reply-To: %s\n", in_reply_to);
  1125.  
  1126.     if (strlen(user_defined_header) > 0)
  1127.         fprintf(filedesc, "%s\n", user_defined_header);
  1128.  
  1129.     add_mailheaders(filedesc);
  1130.  
  1131. #ifndef NO_XHEADER
  1132.     fprintf(filedesc, "X-Mailer: ELM [version %s]\n", version_buff);
  1133. #endif /* !NO_XHEADER */
  1134.  
  1135.     if (form)
  1136.       fprintf(filedesc, "Content-Type: mailform\n");
  1137. #ifdef MIME
  1138.     else if (msg_is_multipart) {
  1139.       fprintf(filedesc, "%s\n", MIME_HEADER);
  1140.       fprintf(filedesc,
  1141.         "%s multipart/mixed; boundary=%s\n", MIME_CONTENTTYPE, MIME_BOUNDARY);
  1142.     }
  1143. #endif /* MIME */
  1144.     else {
  1145. #ifdef    MIME
  1146.       fprintf(filedesc, "%s\n", MIME_HEADER);
  1147.       fprintf(filedesc, "%s text/plain; charset=%s\n",MIME_CONTENTTYPE, charset);
  1148.       fprintf(filedesc, "Content-Transfer-Encoding: %s\n", text_encoding);
  1149. #else
  1150.       fprintf(filedesc, "Content-Type: text\n");
  1151. #endif /* MIME */
  1152.     }
  1153.     fprintf(filedesc, "Content-Length: ");
  1154.     C_L_Position[0] = ftell(filedesc);
  1155.     fprintf(filedesc, "          \n"); /* Print Blanks as Placeholders */
  1156.  
  1157.     putc('\n', filedesc);
  1158.  
  1159.     return((FILE *) filedesc);
  1160. }
  1161.  
  1162. copy_message_across(source, dest, copy)
  1163. FILE *source, *dest;
  1164. int copy;
  1165. {
  1166.     /** Copy the message in the file pointed to by source to the
  1167.         file pointed to by dest.
  1168.         If copy is TRUE, treat as a saved copy of outbound mail. **/
  1169.  
  1170.     int  crypted = FALSE;            /* are we encrypting?  */
  1171.     int  encoded_lines = 0;            /* # lines encoded     */
  1172.     int  line_len;
  1173.     char buffer[SLEN];            /* file reading buffer */
  1174. #ifdef MIME
  1175.     int    text_lines = 0;
  1176.     int    at_boundary = FALSE;
  1177.  
  1178.     C_L_Position[1] = 0L;
  1179.     C_StartData[1] = 0L;
  1180.     C_EndData[1] = 0L;
  1181.  
  1182. #endif /* MIME */
  1183.  
  1184.     while (line_len = mail_gets(buffer, SLEN, source)) {
  1185.       if (buffer[0] == '[') {
  1186.         if (strncmp(buffer, START_ENCODE, strlen(START_ENCODE))==0)
  1187.           crypted = TRUE;
  1188.         else if (strncmp(buffer, END_ENCODE, strlen(END_ENCODE))==0)
  1189.           crypted = FALSE;
  1190.         else if ((strncmp(buffer, DONT_SAVE, strlen(DONT_SAVE)) == 0)
  1191.               || (strncmp(buffer, DONT_SAVE2, strlen(DONT_SAVE2)) == 0)) {
  1192.           if(copy) break;  /* saved copy doesn't want anything after this */
  1193.           else continue;   /* next line? */
  1194. #ifdef MIME
  1195.         } else if (strncmp(buffer, MIME_INCLUDE, strlen(MIME_INCLUDE))==0) {
  1196.           text_lines = 0;
  1197.           if (!at_boundary) {
  1198.         if (C_L_Position[1] != 0L) {
  1199.           C_EndData[1] = ftell(dest);
  1200.           C_L_Position[1] = fseek(dest, C_L_Position[1], 0);
  1201.           fprintf(dest, "%d", C_EndData[1] - C_StartData[1]);
  1202.           fseek(dest, C_EndData[1], 0);
  1203.         }
  1204.         fprintf(dest, "\n--%s\n", MIME_BOUNDARY);
  1205.           }
  1206.           Include_Part(dest, buffer, FALSE);
  1207.           fprintf(dest, "--%s\n", MIME_BOUNDARY);
  1208.           at_boundary = TRUE;
  1209.           continue;
  1210. #endif /* MIME */
  1211.         }
  1212.  
  1213.         if (crypted) {
  1214.           if (! gotten_key++)
  1215.             getkey(ON);
  1216.           else if (! encoded_lines)
  1217.             get_key_no_prompt();        /* reinitialize.. */
  1218.           if (strncmp(buffer, START_ENCODE, strlen(START_ENCODE))) {
  1219.             encode(buffer);
  1220.             encoded_lines++;
  1221.           }
  1222.         }
  1223.       }
  1224.       else if (crypted) {
  1225.         if (batch_only) {
  1226.           printf(catgets(elm_msg_cat, ElmSet, ElmNoEncryptInBatch,
  1227.         "Sorry. Cannot send encrypted mail in \"batch mode\".\n"));
  1228.           leave(0);
  1229.         } else if (! gotten_key++)
  1230.           getkey(ON);
  1231.         else if (! encoded_lines)
  1232.           get_key_no_prompt();        /* reinitialize.. */
  1233.         if (strncmp(buffer, START_ENCODE, strlen(START_ENCODE))) {
  1234.           encode(buffer);
  1235.           encoded_lines++;
  1236.         }
  1237. #ifdef MIME
  1238.       } else {
  1239.         if (text_lines == 0) {
  1240.           if (msg_is_multipart) {
  1241.         if (!at_boundary) {
  1242.            fprintf(dest,"--%s\n",MIME_BOUNDARY);
  1243.         }
  1244.             fprintf(dest, "%s text/plain; charset=%s\n",
  1245.             MIME_CONTENTTYPE, charset);
  1246.         fprintf(dest, "Content-Transfer-Encoding: %s\n", text_encoding);
  1247.         fprintf(dest, "Content-Length: ");
  1248.         C_L_Position[1] = ftell(dest);
  1249.         fprintf(dest, "          \n"); /* Print Placeholders */
  1250.             fprintf(dest, "\n");
  1251.         C_StartData[1] = ftell(dest);
  1252.         at_boundary = FALSE;
  1253.           }
  1254.         }    
  1255.         text_lines++;
  1256. #endif /* MIME */
  1257.           }
  1258.  
  1259. #ifndef DONT_ESCAPE_MESSAGES
  1260.       if (copy && (strncmp(buffer, "From ", 5) == 0)) {
  1261.         /* Add in the > to a From on our copy */
  1262.         fprintf(dest, ">");
  1263.         if (fwrite(buffer, 1, line_len, dest) != line_len) {
  1264.         MoveCursor(LINES, 0);
  1265.         Raw(OFF);
  1266.         Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmWriteFailedCopyAcross,
  1267.             "\nWrite failed in copy_message_across\n"), 0);
  1268.         emergency_exit();
  1269.         }
  1270.       }
  1271. #ifdef NEED_LONE_PERIOD_ESCAPE
  1272.       else if (!copy && strcmp(buffer, ".\n") == 0)
  1273.         /* Because some mail transport agents take a lone period to
  1274.          * mean EOF, we add a blank space on outbound message.
  1275.          */
  1276.         fputs(". \n", dest);
  1277. #endif /* NEED_LONE_PERIOD_ESCAPE */
  1278.         else
  1279. #endif /* DONT_ESCAPE_MESSAGES */
  1280.           if (fwrite(buffer, 1, line_len, dest) != line_len) {
  1281.         MoveCursor(LINES, 0);
  1282.         Raw(OFF);
  1283.         Write_to_screen(catgets(elm_msg_cat, ElmSet, ElmWriteFailedCopyAcross,
  1284.             "\nWrite failed in copy_message_across\n"), 0);
  1285.         emergency_exit();
  1286.         }
  1287.     } 
  1288. #ifdef MMDF
  1289.     if (copy) fputs(MSG_SEPARATOR, dest);
  1290. #else
  1291.     if (copy) fputs("\n", dest);    /* ensure a blank line at the end */
  1292. #endif /* MMDF */
  1293. }
  1294.  
  1295. int
  1296. verify_bounceback()
  1297. {
  1298.     char    ch;
  1299.     char    msg[SLEN];
  1300.  
  1301.     /** Ensure the user wants to have a bounceback copy too.  (This is
  1302.         only called on messages that are greater than the specified 
  1303.         threshold hops and NEVER for non-uucp addresses.... Returns
  1304.         TRUE iff the user wants to bounce a copy back.... 
  1305.      **/
  1306.  
  1307.     MoveCursor(LINES,0);
  1308.     CleartoEOLN();
  1309.     MCsprintf(msg, catgets(elm_msg_cat, ElmSet, ElmBounceOffRemote,
  1310.           "\"Bounce\" a copy off the remote machine? (%c/%c) "),
  1311.           *def_ans_yes, *def_ans_no);
  1312.     ch = want_to(msg, *def_ans_no, LINES, 0);
  1313.     return (ch == *def_ans_yes);
  1314. }
  1315.  
  1316.  
  1317. int
  1318. append_sig(file)
  1319. FILE *file;
  1320. {
  1321.     /* Append the correct signature file to file.  Return TRUE if
  1322.            we append anything.  */
  1323.  
  1324.         /* Look at the to and cc list to determine which one to use */
  1325.  
  1326.     /* We could check the bcc list too, but we don't want people to
  1327.            know about bcc, even indirectly */
  1328.  
  1329.     /* Some people claim that  user@anything.same_domain should be 
  1330.        considered local.  Since it's not the same machine, better be 
  1331.            safe and use the remote sig (presumably it has more complete
  1332.            information).  You can't necessarily finger someone in the
  1333.            same domain. */
  1334.  
  1335.       if (!batch_only && (local_signature[0] || remote_signature[0])) {
  1336.  
  1337.             char filename2[SLEN];
  1338.         char *sig;
  1339.  
  1340.           if (index(expanded_to, '!') || index(expanded_cc,'!'))
  1341.               sig = remote_signature;        /* ! always means remote */
  1342.             else {
  1343.           /* check each @ for @thissite.domain */
  1344.           /* if any one is different than this, then use remote sig */
  1345.           int len;
  1346.           char *ptr;
  1347.           char sitename[SLEN];
  1348.           sprintf(sitename,"@%s",hostfullname);
  1349.           len = strlen(sitename);
  1350.               sig = local_signature;
  1351.               for (ptr = index(expanded_to,'@'); ptr;  /* check To: list */
  1352.               ptr = index(ptr+1,'@')) {
  1353.         if (strincmp(ptr,sitename,len) != 0
  1354.             || (*(ptr+len) != ',' && *(ptr+len) != 0
  1355.             && *(ptr+len) != ' ')) {
  1356.               sig = remote_signature;
  1357.                   break;
  1358.                 }
  1359.               }
  1360.               if (sig == local_signature)           /* still local? */ 
  1361.                 for (ptr = index(expanded_cc,'@'); ptr;   /* check Cc: */
  1362.             ptr = index(ptr+1,'@')) {
  1363.           if (strincmp(ptr,sitename,len) != 0
  1364.               || (*(ptr+len) != ',' && *(ptr+len) != 0 
  1365.               && *(ptr+len) != ' ')) {
  1366.                 sig = remote_signature;
  1367.                     break;
  1368.                   }
  1369.                 }
  1370.             }
  1371.  
  1372.             if (sig[0]) {  /* if there is a signature file */
  1373.           if (sig[0] != '/')
  1374.             sprintf(filename2, "%s/%s", home, sig);
  1375.           else
  1376.             strcpy(filename2, sig);
  1377.           /* append the file - with a news 2.11 compatible */
  1378.           /* seperator if "sig_dashes" is enabled */
  1379.           (void) append(file, filename2, (sig_dashes ? "\n-- \n" : NULL));
  1380.  
  1381.               return TRUE;
  1382.             }
  1383.           }
  1384.  
  1385. return FALSE;
  1386.  
  1387. }
  1388.  
  1389.